package dao

import models.Tables._
import play.api.db.slick.{DatabaseConfigProvider, HasDatabaseConfigProvider}
import slick.jdbc.JdbcProfile
import tool.Pojo._
import tool.Tool

import javax.inject.Inject
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future


/**
 * Created by yz on 2017/6/1.
 */
class BrowsePathwayDao @Inject()(protected val dbConfigProvider: DatabaseConfigProvider) extends
  HasDatabaseConfigProvider[JdbcProfile] {

  import profile.api._

  type MyRow = BrowsePathwayRow
  val table = BrowsePathway

  def insertAll(circallpositions: Seq[MyRow]): Future[Unit] = db.run(table ++=
    circallpositions).map(_ => ())

  def deleteAll(): Future[Unit] = db.run(table.delete).map(_ => ())

  def selectAll = {
    db.run(table.result)
  }

  def selectAll(ids: List[String]) = db.run(table.
    filter(_.pathwayId.inSetBind(ids)).result.map(_.toList))

  //  def selectSamples: Future[Seq[String]] = {
  //    db.run(table.map(_.exosomesamples).distinct.result).
  //      map(x => x.flatMap(_.split(",")).distinct.filter(_ != ""))
  //  }

  def selectDiffSamples: Future[Seq[String]] = {
    db.run(table.map(_.diffGroup).distinct.result).
      map(x => x.flatMap(_.split(",")).distinct.filter(_ != ""))
  }

  def selectById(v: String) = {
    db.run(table.filter(_.pathwayId === v).result.head)
  }

  def selectAllMsigdbSource: Future[Seq[String]] = {
    db.run(table.map(_.msigdbSource).distinct.result)
  }

  def selectAllDiffGroup = {
    db.run(table.map(_.diffGroup).distinct.result.map(_.toList))
  }

  def selectAllName: Future[Seq[String]] = {
    db.run(table.map(_.pathwayName).distinct.result)
  }

  def selectAllId: Future[Seq[String]] = {
    db.run(table.map(_.pathwayId).distinct.result)
  }

  def searchAllByIdOrName(ids: Seq[String]) = {
    db.run(table.filter { x =>
      x.pathwayId.inSetBind(ids) || x.pathwayName.inSetBind(ids)
    }.result)
  }

  def selectAll(data: PathwayData, pageData: PageData) = {
    val filterData = table.filterOpt(data.sources) { (x, ys) =>
      val allB = ys.map { y =>
        x.msigdbSource.like(s"%${y}%")
      }
      allB.reduceLeft((t, z) => t || z)
    }.filterOpt(data.diffSamples) { (x, ys) =>
      val allB = ys.map { y =>
        x.diffGroup.like(s"%${y}%")
      }
      val b = data.diffSamplesMethod match {
        case "union" => allB.reduceLeft((t, z) => t || z)
        case "inter" => allB.reduceLeft((t, z) => t && z)
      }
      b
    }.filterOpt(pageData.search) { (x, y) =>
      val columns = List("pathway_id", "pathway_name", "msigdb_source", "diff_group")
      columns.map { columnName =>
        x.getStrColumn(columnName).like(s"%${y}%")
      }.reduceLeft((x, y) => x || y)
    }
    val intColumnNames = List()
    val doubleColumnNames = List("tumor_mean", "benign_mean", "health_mean", "urine_mean",
      "csf_mean", "bile_mean")
    val sortData = data.sort match {
      case None => filterData
      case Some(x) =>
        val columnName = Tool.getTrueColumnName(x)
        val order = data.order
        columnName match {
          case x if intColumnNames.contains(columnName) => order match {
            case "asc" => filterData.sortBy { y =>
              y.getIntColumn(columnName)
            }
            case "desc" => filterData.sortBy { x =>
              x.getIntColumn(columnName).desc
            }
          }
          case x if doubleColumnNames.contains(columnName) => order match {
            case "asc" => filterData.sortBy { y =>
              y.getDoubleColumn(columnName)
            }
            case "desc" => filterData.sortBy { x =>
              x.getDoubleColumn(columnName).desc
            }
          }
          case _ => order match {
            case "asc" => filterData.sortBy { y =>
              y.getStrColumn(columnName)
            }
            case "desc" => filterData.sortBy { x =>
              x.getStrColumn(columnName).desc
            }
          }
        }
    }
    val finalData = sortData
    val countF = finalData.length.result
    val resultF = finalData.drop(pageData.offset).take(pageData.limit).result
    val f = countF.zip(resultF)
    db.run(f)
  }


}
